package data_structs;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.TreeMap;

public class HashTable<E> implements Serializable {

	//Global variables
	private TreeMap<String,ArrayList<E>>[] hashArr;
	private int tableSize;
	private int numObjects;
	private int numKeys = 0;
	
	public HashTable() {
		this(9973);
	}
	
	public HashTable(int tableSize) {
		
		if( tableSize <= 0) {
			this.tableSize = 9973;
			System.err.println("Table size must be a positive integer. Setting to 9973.");
		}
		else
			this.tableSize = tableSize;
		numObjects = 0;
		hashArr = new TreeMap[tableSize];
		for( int i = 0; i < tableSize; i++ )
			hashArr[i] = new TreeMap();
	}
	
	public void add(String s, E obj) {
		int index = (obj.hashCode() & 0x7FFFFFFF) % tableSize;
		TreeMap<String,ArrayList<E>> tree = hashArr[index];
		//Check if object does not already exists
		if( !tree.containsKey(s) ) {
			ArrayList<E> list = new ArrayList<E>();
			list.add(obj);
			tree.put(s, list);
			numKeys++;
		}
		else {
			ArrayList<E> list = tree.get(s);
			list.add(obj);
		}
		numObjects++;
	}

	//Return the list of found objects' toString
	public ArrayList<E> contains(String s, E obj) {
		if( isEmpty() )
			return null;
		
		int index = (obj.hashCode() & 0x7FFFFFFF) % tableSize;
		TreeMap<String,ArrayList<E>> tree = hashArr[index];
		
		return tree.get(s);
	}

	public E remove(E obj) {
		throw new UnsupportedOperationException("Remove not allowed.");
	}

	public TreeMap<String,ArrayList<E>>[] allElements() {
		return hashArr;
	}

	public int numObjects() {
		return numObjects;
	}
	
	public int numKeys() {
		return numKeys;
	}

	public boolean isEmpty() {
		return numObjects == 0;
	}

	//Print out info about hash table
	public String hashStatus() {
		int zero, least5, least10, least100, more100;
		zero = least5 = least10 = least100 = more100 = 0;
		for( int i = 0; i < tableSize; i++ ) {
			int num = hashArr[i].size();
			if( num == 0 ) zero++;
			else if( num <= 5 ) least5++;
			else if( num <= 10 ) least10++;
			else if( num <= 100 ) least100++;
			else more100++;
		}
		double pctNotUsed = (double) zero/tableSize*100;
		return "***HASH STATUS***\n$" +
				"Trees with no keys: "+zero+"\n$" +
				"Trees with 1 to 5 keys: "+least5+"\n$" +
				"Trees with 6 to 10 keys: "+least10+"\n$" +
				"Trees with 11 to 100 keys: "+least100+"\n$" +
				"Trees with more than 100 keys: "+more100+"\n$" +
				"Table Size: "+tableSize+"\n$" +
				"Percentage not in use: "+pctNotUsed+"%\n";
	}
}
